package server

import (
	"context"
	"fmt"

	. "starsine.cn/appTpl/cmn/defs"
	"starsine.cn/appTpl/cmn/logs"
	"starsine.cn/appTpl/cmn/pubsub"
	"starsine.cn/appTpl/svccenter/registry/grpc/scregistryproto"
	"starsine.cn/appTpl/svccenter/registry/registrypubsub"
	"starsine.cn/appTpl/svccenter/registry/svcmng"
	. "starsine.cn/appTpl/svccenter/registry/svcmng/iservice"
)

type RegistryProtoServer struct {
	scregistryproto.UnimplementedRegistryProtoServer
}

func (p *RegistryProtoServer) SvcRegist(ctx context.Context, in *scregistryproto.SvcInfo) (*scregistryproto.RegistryInfo, error) {
	svc, err := svcmng.ServiceReg(in.SvcType, in.Name, in.UserSpace, SvcData{
		RpcAddr: in.RpcAddr,
		Version: in.Version,
	})
	if err != nil {
		logs.Warnf("svc(%s-%s-%s) register fail, err: %s", in.UserSpace, in.SvcType, in.Name, err)
		return &scregistryproto.RegistryInfo{}, fmt.Errorf("svc(%s-%s-%s) register fail, err: %s", in.UserSpace, in.SvcType, in.Name, err)
	}
	svc.Start(nil)

	reply := &scregistryproto.RegistryInfo{
		InstanceID: svc.GetInstanceID(),
	}
	return reply, nil
}

func (p *RegistryProtoServer) SvcGet(ctx context.Context, in *scregistryproto.SvcGetReq) (*scregistryproto.SvcGetRes, error) {
	v := svcmng.GetServiceListByType(in.SvcType)

	svcs := []*scregistryproto.SvcAddr{}
	for _, vv := range v {
		if vv.GetSvcData().Version >= in.Version {
			svcs = append(svcs, &scregistryproto.SvcAddr{
				InstanceID: vv.GetInstanceID(),
				RpcAddr:    vv.GetSvcData().RpcAddr,
			})
		}
	}
	return &scregistryproto.SvcGetRes{
		SvcAddr: svcs,
	}, nil
}

func (RegistryProtoServer) SvcGetAll(ctx context.Context, in *scregistryproto.SvcGetAllReq) (*scregistryproto.SvcGetAllRes, error) {
	svcs := map[string]*scregistryproto.SvcInfo{}
	svcmng.ForEach(func(k string, v IService) bool {
		svcs[k] = &scregistryproto.SvcInfo{
			UserSpace: v.GetUserSpace(),
			SvcType:   v.GetServiceType(),
			Name:      v.GetName(),
			RpcAddr:   v.GetRpcAddr(),
			Version:   v.GetVersion(),
		}
		return true
	})

	return &scregistryproto.SvcGetAllRes{
		Svcs: svcs,
	}, nil
}

func (p *RegistryProtoServer) SvcHeartbeat(ctx context.Context, in *scregistryproto.HeartbeatReq) (*scregistryproto.HeartbeatRes, error) {
	_, ok := svcmng.GetService(in.InstanceID)
	if !ok {
		return &scregistryproto.HeartbeatRes{
			Succ: false,
		}, nil
	}

	return &scregistryproto.HeartbeatRes{
		Succ: true,
	}, nil
}

func (p *RegistryProtoServer) SubSvcRegister(ctx context.Context, in *scregistryproto.SubSvcRegisterReq) (*scregistryproto.Res, error) {
	svc, ok := svcmng.GetService(in.InstanceID)
	if ok {
		registrypubsub.GetPubSub().Sub(in.Topic, pubsub.Client{
			IsAlways: in.IsAlways,
			IClient:  svc,
		})
		return &scregistryproto.Res{
			Succ: true,
		}, nil
	}

	return &scregistryproto.Res{
		Succ: false,
	}, nil
}

func (p *RegistryProtoServer) SubSvcUpdate(ctx context.Context, in *scregistryproto.SubSvcUpdateReq) (*scregistryproto.Res, error) {
	svc, ok := svcmng.GetService(in.InstanceID)
	if !ok {
		return &scregistryproto.Res{
			Succ: false,
		}, nil
	}

	registrypubsub.GetPubSub().Sub(in.Topic, pubsub.Client{
		IsAlways: in.IsAlways,
		IClient:  svc,
	})
	return &scregistryproto.Res{
		Succ: true,
	}, nil
}

func (p *RegistryProtoServer) UnSubSvcUpdate(ctx context.Context, in *scregistryproto.SubSvcUpdateReq) (*scregistryproto.Res, error) {
	registrypubsub.GetPubSub().UnSub(in.Topic, in.InstanceID)
	return &scregistryproto.Res{
		Succ: true,
	}, nil
}
